#include "jnihelp.h"

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "lame.h"

#ifdef __cplusplus
extern "C" {
#endif


static lame_global_flags *lame = NULL;

void lame_utils_init(
        JNIEnv *env, jclass cls, jint inSamplerate, jint inChannel, jint outSamplerate,
        jint outBitrate, jint quality) {
    if (lame != NULL) {
        lame_close(lame);
        lame = NULL;
    }
    lame = lame_init();
    lame_set_in_samplerate(lame, inSamplerate);
    lame_set_num_channels(lame, inChannel);//输入流的声道
    lame_set_out_samplerate(lame, outSamplerate);
    lame_set_brate(lame, outBitrate);
    lame_set_quality(lame, quality);
    lame_init_params(lame);
}

jint lame_utils_encode(
        JNIEnv *env, jclass cls, jshortArray buffer_l, jshortArray buffer_r,
        jint samples, jbyteArray mp3buf) {
    jshort *j_buffer_l = (*env)->GetShortArrayElements(env, buffer_l, NULL);

    jshort *j_buffer_r = (*env)->GetShortArrayElements(env, buffer_r, NULL);

    const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf);
    jbyte *j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL);

    int result = lame_encode_buffer(lame, j_buffer_l, j_buffer_r,
                                    samples, j_mp3buf, mp3buf_size);

    (*env)->ReleaseShortArrayElements(env, buffer_l, j_buffer_l, 0);
    (*env)->ReleaseShortArrayElements(env, buffer_r, j_buffer_r, 0);
    (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0);

    return result;
}

jint lame_utils_flush(
        JNIEnv *env, jclass cls, jbyteArray mp3buf) {
    const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf);
    jbyte *j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL);

    int result = lame_encode_flush(lame, j_mp3buf, mp3buf_size);

    (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0);

    return result;
}

void lame_utils_close
        (JNIEnv *env, jclass cls) {
    lame_close(lame);
    lame = NULL;
}

#define JNI_CLASS_NAME "cn/com/infohold/android/jni/MP3Lame"
static const JNINativeMethod JNI_METHODS[] = {
        {"init",   "(IIIII)V",   (void *) lame_utils_init},
        {"encode", "([S[SI[B)I", (void *) lame_utils_encode},
        {"flush",  "([B)I",      (void *) lame_utils_flush},
        {"close",  "()V",        (void *) lame_utils_close},
};


jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
    JNIEnv *env = NULL;

    //printf("OS Bit = %d \n",sizeof(int*)*8);
    if ((*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);

    if (!registerNatives(env, JNI_CLASS_NAME, JNI_METHODS)) {
        return -1;
    }

    return JNI_VERSION_1_4;
}

jint JNI_OnUnLoad(JavaVM *jvm, void *reserved) {

}


#ifdef __cplusplus
}
#endif
